package com.wt.admin.service.image.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import com.wt.admin.code.image.ImageClassification3100;
import com.wt.admin.config.ConstVar;
import com.wt.admin.config.prop.IndexProp;
import com.wt.admin.config.socket.WebSocketSessionManager;
import com.wt.admin.domain.dto.image.ImageClassificationDTO;
import com.wt.admin.domain.dto.image.ImageFeaturesDTO;
import com.wt.admin.domain.entity.image.ImageClassificationEntity;
import com.wt.admin.domain.entity.image.ImageItemEntity;
import com.wt.admin.domain.vo.image.ImageClassificationListVO;
import com.wt.admin.domain.vo.image.ImageClassificationVO;
import com.wt.admin.domain.vo.image.ImageFeaturesListVO;
import com.wt.admin.domain.vo.image.ImageFeaturesVO;
import com.wt.admin.domain.vo.socket.ProgressVO;
import com.wt.admin.domain.vo.socket.SocketVO;
import com.wt.admin.domain.vo.sys.UserVO;
import com.wt.admin.service.file.UploadFileService;
import com.wt.admin.service.image.ImageClassificationService;
import com.wt.admin.service.image.ImageFeaturesService;
import com.wt.admin.service.image.ImageItemService;
import com.wt.admin.service.image.ImageProxyService;
import com.wt.admin.service.language.ClassificationService;
import com.wt.admin.util.AssertUtil;
import com.wt.admin.util.PageUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;
import java.util.Map;

@Service("imageProxy")
@Slf4j
public class ImageProxyServiceImpl implements ImageProxyService , UploadFileService {

    @Resource
    private ImageClassificationService imageClassificationService;
    @Resource
    private ImageFeaturesService imageFeaturesService;
    @Resource
    private ImageItemService imageItemService;
    @Resource
    private ClassificationService classificationService;
    @Resource
    private ImageTrainingService imageTrainingService;
    @Autowired
    private IndexProp indexProp;


    @Override
    public ImageItemService getImageItemService() {return imageItemService;}
    @Override
    public ImageFeaturesService getImageFeaturesService() {return imageFeaturesService;}
    @Override
    public ImageClassificationService getImageClassificationService() {return imageClassificationService;}


    @Override
    public void init(){
        log.debug("图像初始化开始");
        List<ImageClassificationVO> list = imageClassificationService.list(null);
        list.parallelStream().forEach(i -> imageTrainingService.init(i));
        log.debug("图像初始化完毕");
    }


    @Transactional
    @Override
    public ImageFeaturesVO featuresEdit(ImageFeaturesDTO data) {
        imageFeaturesService.edit(data);
        return null;
    }

    @Override
    public ImageFeaturesListVO featuresList(PageUtil.PageDTO<ImageFeaturesDTO> data) {
        return ImageFeaturesListVO.builder()
                .features(imageFeaturesService.list(data))
                .classs(classificationService.list(null))
                .build();
    }

    @Transactional
    @Override
    public ImageFeaturesVO featuresDel(ImageFeaturesDTO data) {
        imageFeaturesService.del(data);
        return null;
    }

    @Override
    public ImageClassificationVO imageClassificationDel(ImageClassificationDTO data) {
        int count = imageItemService.findByCountImageClassificationId(data.getId());
        AssertUtil.Boolean.isTrue(count > 0, ImageClassification3100.CODE_3104);
        imageClassificationService.del(data);
        return null;
    }

    @Override
    public ImageClassificationListVO list(ImageClassificationDTO data) {
        return ImageClassificationListVO.builder()
                .imageClasss(imageClassificationService.list(data))
                .classs(classificationService.list(null))
                .build();
    }

    @Async("newAsyncExecutor")
    @Transactional
    @Override
    public void imageTraining(ImageClassificationDTO data) {
        try {
            send("图像训练",0);
            AssertUtil.objIsNull(data.getId(), ImageClassification3100.CODE_3103);
            List<ImageItemEntity> imageItemVOList = imageItemService.findByClassificationId(data.getId());
            int maxFeaturesNum = imageItemVOList.stream()
                    .peek(i -> i.setStatus(ConstVar.Image.STATUS_20))
                    .mapToInt(ImageItemEntity::getFeaturesNum).max().orElse(0);
            data.getYoloConfig().setTypeNub(maxFeaturesNum);
            data.setTraining(true);
            send("图像训练",30);
            imageTrainingService.training(data, imageItemVOList);
            imageClassificationService.edit(data);
            send("图像训练",90);
            imageItemService.updateBatch(imageItemVOList);
            send("图像训练",100);
        } catch (Exception e) {
            send("图像训练",-100);
            log.error("训练失败 {}",e.getMessage());
        }
    }

    @SneakyThrows
    @Override
    public String testTraining(MultipartFile file,Integer id) {
        String name = file.getOriginalFilename();
        String path = "test/";
        name =  RandomUtil.randomNumbers(12) + (name.contains(".") ? name.substring(name.indexOf(".")): "");
        String absPath = indexProp.getFiles().getSavePath()+path+name;
        File tempFile = FileUtil.touch(absPath);
        ImageClassificationEntity byId = imageClassificationService.byId(id);
        file.transferTo(tempFile);
        checkImagePixel(List.of(absPath),byId);
        imageTrainingService.testTraining(id,tempFile,indexProp.getFiles().getSavePath()+path+name);
        return indexProp.getFiles().getSource().replace("*","") + path + "/" + name;
    }

    @Override
    public boolean exec(String path, MultipartFile file, Map<String, String[]> map, UserVO userVO) {
        String classificationId = map.get("classificationId")[0];
        String languageClassificationId = map.get("languageClassificationId")[0];
        ImageClassificationEntity imageClassificationEntity = imageClassificationService.byId(Integer.valueOf(classificationId));
        checkImagePixel(List.of(path),imageClassificationEntity);
        ImageItemEntity imageItemEntity = new ImageItemEntity();
        imageItemEntity.setImageUrl(path);
        imageItemEntity.setStatus(ConstVar.Image.STATUS_10);
        imageItemEntity.setClassificationId(Integer.valueOf(classificationId));
        imageItemEntity.setLanguageClassificationId(Integer.valueOf(languageClassificationId));
        imageItemService.saveOne(imageItemEntity);
        return true;
    }

    @Transactional
    @Override
    public boolean batchExec(List<String> path, MultipartFile[] file, Map<String, String[]> map, UserVO userVO) {
        String classificationId = map.get("classificationId")[0];
        String languageClassificationId = map.get("languageClassificationId")[0];
        ImageClassificationEntity imageClassificationEntity = imageClassificationService.byId(Integer.valueOf(classificationId));
        checkImagePixel(path,imageClassificationEntity);
        List<ImageItemEntity> list = path.stream().map(i -> {
            ImageItemEntity imageItemEntity = new ImageItemEntity();
            imageItemEntity.setImageUrl(i);
            imageItemEntity.setStatus(ConstVar.Image.STATUS_10);
            imageItemEntity.setClassificationId(Integer.valueOf(classificationId));
            imageItemEntity.setLanguageClassificationId(Integer.valueOf(languageClassificationId));
            return imageItemEntity;
        }).toList();
        imageItemService.saveBatchs(list);
        return true;
    }

    private void checkImagePixel(List<String> path,ImageClassificationEntity img){
        path.parallelStream().forEach(i -> {
            File file = FileUtil.file(ImageItemEntity.getImageAbsURL(i));
            if (!FileUtil.exist(file)) {
                return;
            }
            try {
                Thumbnails.of(file)
                        .size(img.getImageWidth().intValue(), img.getImageHeight().intValue())
                        .keepAspectRatio(false)
                        .outputQuality(1.0)
                        .toFile(file);
            }catch (Exception e){
                log.error("图片缩放失败 :{}",e.getMessage());
            }
        });

    }

    private void send(String title, int progress){
        WebSocketSessionManager.sendToAll(new SocketVO<ProgressVO>
                (ConstVar.Socket.PROGRESS,ProgressVO.set(title,progress)).getJson());
    }

}
